<!--
  echarts 热力图
  注意点：
    eachrts 实例化后的对象是以 id 为键值，保存在 window 上的，类似全局变量。因此在同一个页面多次引入相同组件的时候，必须传递id，不然会存在冲突（全局变量保存chart数据，会互相影响）。
-->

<template>
  <div
    :class="'e-heatmap-wrap ' + wrapId"
    :key="wrapId"
    :id="wrapId"
    :ref="wrapId"
    :style="{ height: height, width: width }"
  >
    <div :id="id" :ref="id" :class="'chart ' + className"></div>
    <div class="right-menu-wrap" ref="rightMenu">
      <slot name="right-menu"></slot>
    </div>
  </div>
</template>

<script>
import echarts from 'echarts'
import { isFunction, merge, isEmpty, each, every, isArray, min, max } from 'lodash'
// 图标跟随视窗变化而变化
import chartResize from '@/mixins/chartResize'
import config from '@/config'
require('echarts/extension/bmap/bmap')

export default {
  name: 'e-heatmap',
  mixins: [chartResize],
  props: {
    id: {
      type: String,
      default: 'e-heatmap'
    },
    className: {
      type: String,
      default: ''
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '100%'
    },
    fetchData: {
      type: Function
    },
    chartData: {
      type: Object,
      default: null
    },
    loadingStyle: {
      type: Object,
      default: () => ({})
    },
    shrink: {
      // 收缩
      type: Boolean
    },
    markPoints: {
      type: Array
    },
    drawing: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    wrapId() {
      return this.id + '-chart'
    },
    markerPointList() {
      const flag = every(this.markPoints, item => isArray(item))
      if (flag) {
        return this.markPoints
      }
      return [this.markPoints]
    }
  },
  data() {
    return {
      overlays: []
    }
  },
  watch: {
    chartData: {
      handler() {
        window[this.id].hideLoading()
        this.chartRest()
      },
      deep: true
    },
    /**
     * desc: 页面收缩时，执行图表重新渲染
     * param {type}
     * return:
     */
    shrink() {
      this.resize()
    },
    /**
     * desc: 跳动覆盖物
     * param {type}
     * return: void
     */
    markPoints() {
      this.setMapMark()
    }
  },
  beforeDestroy() {
    if (!window[this.id]) {
      return
    }
    window[this.id + '-drawingManager'].removeEventListener('overlaycomplete', this.overlaycomplete)
    window[this.id].off('click')
    window[this.id].off('dblclick')
    window[this.id].off('finished')
    window[this.id].dispose()
    window[this.id] = null
  },
  mounted() {
    // 初始化echarts
    window[this.id] = echarts.init(document.getElementById(this.id), config.echartsthemeName)
    // 图标请求数据
    if (isFunction(this.fetchData)) {
      this.getChartData()
    }
    // 图表渲染前数据就已存在
    if (!isEmpty(this.chartData)) {
      this.initChart()
    }
    this.$nextTick(() => {
      this.bindEvent()
    })
  },
  methods: {
    /**
     * desc: 当开启双击地图覆盖物的时候，关闭地图的双击放大
     * param {type}
     * return:
     */
    closeBMapZoom() {
      const { _events } = this
      if (_events['q-dblClick']) {
        window[this.id + '-bMap'].disableDoubleClickZoom() // 关闭地图缩放功能
      }
    },
    /**
     * desc: 图标绑定事件
     * param {type}
     * return: void
     */
    bindEvent() {
      const _this = this
      let timeFn = null
      // 单击事件
      window[this.id].on('click', function(params) {
        clearTimeout(timeFn)
        timeFn = setTimeout(function() {
          _this.clickHandle(params)
        }, 300)
      })
      // 双击事件
      window[this.id].on('dblclick', function(params) {
        _this.closeBMapZoom() // 双击关闭地图缩放功能
        clearTimeout(timeFn)
        _this.dblClickHandle(params)
      })
      // chart加载完成监听
      window[this.id].on('finished', this.chartFinished)
    },
    /**
     * desc: 显示图表加载loading
     * param {type}
     * return:
     */
    showLoading() {
      window[this.id].showLoading(merge({}, config.echartsLoadingStyle, this.loadingStyle))
    },
    /**
     * desc: 图表重置
     * param {type}
     * return:
     */
    chartRest() {
      this.$nextTick(() => {
        this.initChart()
      })
    },
    /**
     * desc: 初始化图表
     * param {type}
     * return: void
     */
    initChart() {
      window[this.id].setOption(this.chartData, true)
      window[this.id + '-bMap'] = window[this.id]
        .getModel()
        .getComponent('bmap')
        .getBMap()
      if (!isEmpty(this.markPoints)) {
        this.setMapMark()
      }

      if (this.drawing) {
        this.drawingHandle()
      }
    },
    /**
     * desc: 获取图表数据
     * param {type}
     * return: void
     */
    getChartData() {
      this.showLoading()
      this.fetchData()
    },
    /**
     * @msg: 添加覆盖物
     * @param {type}
     * @return:
     */
    setMapMark() {
      window[this.id + '-bMap'] = window[this.id]
        .getModel()
        .getComponent('bmap')
        .getBMap()
      const allOverlays = window[this.id + '-bMap'].getOverlays()
      // 清除覆盖物
      each(allOverlays, item => {
        if (item.hasOwnProperty('Lb') && item.Lb === 'overlay') {
          window[this.id + '-bMap'].removeOverlay(item)
        }
      })
      // 批量添加多个覆盖物
      each(this.markerPointList, item => {
        // eslint-disable-next-line no-undef
        const point = new BMap.Point(...item)
        // eslint-disable-next-line no-undef
        let marker = new BMap.Marker(point) // 创建标注
        window[this.id + '-bMap'].addOverlay(marker) // 将标注添加到地图中
        window[this.id + '-bMap'].getPanes().markerPane.style.zIndex = 500
        // eslint-disable-next-line no-undef
        marker.setAnimation(BMAP_ANIMATION_BOUNCE) // 跳动的动画
      })
    },
    /**
     * desc: 单击事件
     * param {params} 图表点击返回对象
     * return: void
     */
    clickHandle(params) {
      this.clearOverlay()
      this.$emit('q-click', params)
    },
    /**
     * desc: 双击事件
     * param {params} 图表点击返回对象
     * return: void
     */
    dblClickHandle(params) {
      this.$emit('q-dblClick', params)
    },
    /**
     * desc: 图表加载完成
     * param {type}
     * return: void
     */
    chartFinished() {
      this.$emit('q-finished', window[this.id])
    },
    drawingHandle() {
      window[this.id + '-bMap'] = window[this.id].getModel().getComponent('bmap').getBMap()
      const styleOptions = {
        strokeColor: '#f8f8f8', // 边线颜色。
        fillColor: '#fff', // 填充颜色。当参数为空时，圆形将没有填充效果。
        strokeWeight: 3, // 边线的宽度，以像素为单位。
        strokeOpacity: 0.8, // 边线透明度，取值范围0 - 1。
        fillOpacity: 0.5, // 填充的透明度，取值范围0 - 1。
        strokeStyle: 'solid' // 边线的样式，solid或dashed。
      }
      // eslint-disable-next-line no-undef
      window[this.id + '-drawingManager'] = new BMapLib.DrawingManager(window[this.id + '-bMap'], {
        isOpen: false, // 是否开启绘制模式
        enableDrawingTool: true, // 是否显示工具栏
        drawingToolOptions: {
          // eslint-disable-next-line no-undef
          anchor: BMAP_ANCHOR_TOP_RIGHT, // 位置
          // eslint-disable-next-line no-undef
          offset: new BMap.Size(5, 5), // 偏离值
          // eslint-disable-next-line no-undef
          drawingModes: [BMAP_DRAWING_RECTANGLE],
          // eslint-disable-next-line no-undef
          drawingTypes: [BMAP_DRAWING_RECTANGLE],
          scale: 0.6
        },
        circleOptions: styleOptions, // 圆的样式
        polylineOptions: styleOptions, // 线的样式
        polygonOptions: styleOptions, // 多边形的样式
        rectangleOptions: styleOptions // 矩形的样式
      })
      window[this.id + '-drawingManager'].addEventListener('overlaycomplete', this.overlaycomplete)
    },
    /**
     * 清除地图选取区域
     * @return {[type]} [description]
     */
    clearOverlay () {
      window[this.id + '-bMap'].removeOverlay(this.overlays[0])
      this.overlays.length = 0
    },
    /**
     * 鼠标框选区域获取经纬度
     * @param  {[type]} e [description]
     * @return {[type]}   [description]
     */
    overlaycomplete (e) {
      this.clearOverlay()
      this.overlays.push(e.overlay)
      const xPath = []
      const yPath = []
      const paths = e.overlay.getPath()
      each(paths, path => {
        const { lng, lat } = path
        xPath.push(lat)
        yPath.push(lng)
      })
      const xMinSize = min(xPath)
      const xMaxSize = max(xPath)
      const yMinSize = min(yPath)
      const yMaxSize = max(yPath)
      this.$emit('checkArea', {
        xMinSize,
        xMaxSize,
        yMinSize,
        yMaxSize
      })
    },
    resize() {
      window[this.id].resize()
    }
  }
}
</script>
<style lang="less">
.e-heatmap-wrap {
  .chart {
    width: 100%;
    height: 100%;
  }
}
</style>
